package lumis.portal.webfilereplication;

import javax.persistence.NoResultException;

import lumis.portal.PortalException;
import lumis.portal.authentication.SessionConfig;
import lumis.portal.channel.ChannelConfig;
import lumis.portal.channel.ChannelWebResource;
import lumis.portal.file.FileConfig;
import lumis.portal.file.FileManager;
import lumis.portal.filesystem.PortalFile;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.page.PageConfig;
import lumis.portal.page.PageWebResource;
import lumis.portal.serviceinstance.ServiceInstanceConfig;
import lumis.portal.transaction.ITransaction;
import lumis.portal.transaction.PortalTransactionFactory;
import lumis.portal.url.WebResource;

/**
 * Helper for WebFileReplication that handles the channel filter conditions.
 * Provides the matches method that decides whether the given PortalFile must
 * be processed or not given a value to channel filter.
 * There are two situations when the given PortalFile must be processed:
 * <ul>
 * <li>when the PortalFile corresponds to a page cache inside the channel
 * filter tree</li>
 * <li>when the PortalFile corresponds to a file associated to a service
 * instance inside the channel filter tree</li>
 * </ul>
 * Also, when the filter is null or empty, any PortalFile must be processed.
 * 
 * @version $Revision: 13093 $ $Date: 2011-05-28 18:40:18 -0300 (Sat, 28 May 2011) $
 * @since 6.0.0
 */
class FilterChannelHelper
{
	/**
	 * Returns true if the PortalFile is in the tree of the channel filter.
	 * @param file				instance of PortalFile.
	 * @param filterChannelId	the filter channel id.
	 * @return	true if the PortalFile is in the tree of the channel filter.
	 * @throws PortalException
	 * @since 6.0.0
	 */
	public static boolean matches(PortalFile file, String filterChannelId)
							throws FileReplicationException
	{
		if ((filterChannelId == null) || (filterChannelId.equals("")))
		{
			return true;
		}	
				
		ITransaction transaction = PortalTransactionFactory.createTransaction();
		try
		{
			try
			{
				transaction.begin();
				
				boolean match = false;
				
				String channelId = findPortalFileChannel(file);
				if ((channelId != null) && (!channelId.equals(""))) {
					match = isChannelInFilterChannelTree(filterChannelId, channelId);	
				}				
				
				if (!match)
				{
					String siChannelId = findFileServiceInstanceChannel(file);
					if ((siChannelId != null) && (!siChannelId.equals("")))
					{
						match = isChannelInFilterChannelTree(filterChannelId, siChannelId);
					}					
				}
				
				transaction.commit();
				
				return match;				
			}
			finally
			{
				transaction.dispose();
			}
		}
		catch (PortalException e)
		{
			throw new FileReplicationException(e);
		}
	}
	
	/**
	 * Finds the channel id of the PortalFile.
	 * @param file	an instance of PortalFile.
	 * @return	the channel id of the PortalFile.
	 * @since 6.0.0
	 */
	protected static String findPortalFileChannel(PortalFile file)
	{
		WebResource webResource = null;
		try
		{
			// TODO: using named query hard-coded until URLManager or PageCacheManager provides
			// method for obtaining the web resource by the cache file path
			webResource = (WebResource) ManagerFactory.getEntityManager()
															.createNamedQuery("findWebResourceByFilePath")
															.setParameter("filePath", "/" + file.getPortalFilePath().getRelativePath())
															.getSingleResult();
		}
		catch (NoResultException e)
		{
			return null;
		}
		
		String channelId;
		if (webResource instanceof ChannelWebResource)
		{
			channelId = ((ChannelWebResource) webResource).getChannelId();			
		}
		else
		{
			PageConfig pageConfig = ((PageWebResource) webResource).getPage();
			channelId = pageConfig.getChannelId();
		}
		return channelId;
	}
	
	/**
	 * Returns true if the channel filter id is in the tree of the given channel id parameter.
	 * @param channelId	the channel id.
	 * @return	true if the channel filter id is in the channel id tree otherwise returns false.
	 * @since 6.0.0
	 */
	protected static boolean isChannelInFilterChannelTree(
				String filterChannelId, 
				String channelId)
			throws PortalException
	{
		if (channelId.equals(filterChannelId)) 
		{
			return true;
		}
		else
		{
			ChannelConfig channelConfig = ManagerFactory.getChannelManager().get(
															SessionConfig.getCurrentSessionConfig(), 
															channelId, 
															PortalTransactionFactory.getCurrentTransaction());
			String parentChannelId = channelConfig.getParentId();
			if (parentChannelId == null)
			{
				return false;
			}
			else
			{
				return isChannelInFilterChannelTree(filterChannelId, channelConfig.getParentId());
			}			
		}
	}

	/**
	 * Finds the FileConfig by the path and then finds the channel id of the service instance.
	 * @param path	the path.
	 * @return		the channel id.
	 * @throws PortalException
	 * @since 6.0.0
	 */
	protected static String findFileServiceInstanceChannel(PortalFile file)
								throws PortalException
	{		
		String filepath = file.getPortalFilePath().getRelativePath();
		if (filepath.startsWith("/"))
		{
			filepath = filepath.substring(1);
		}
		
		FileConfig fileConfig = ((FileManager) ManagerFactory.getFileManager()).findByFullPath(SessionConfig.getCurrentSessionConfig(), filepath, PortalTransactionFactory.getCurrentTransaction());
		
		String serviceInstanceChannelId = null;
		if (fileConfig != null)
		{
			ServiceInstanceConfig sic = ManagerFactory.getServiceInstanceManager().get(fileConfig.getServiceInstanceId(), PortalTransactionFactory.getCurrentTransaction());
			serviceInstanceChannelId = sic.getChannelId();			
		}
		
		return serviceInstanceChannelId;
	}
}